
/**
 * 映射类型
 * 新类型以相同的形式去转换旧类型里每个属性
 * example: Partial/Required/Readonly
 */

// '-?:' 字符语法的作用就是这样，标记映射类型的属性为必需。它只能在映射类型中使用，
// 在其他类型中使用会报错，上面的 Required<T> 就是一个映射类型

// 1. 获取函数返回类型
type myReturnType<T> = T extends (...arg: any) => infer Return ? Return : never

// 2. 实现 Exclude ，从联合类型T中排除U的类型成员，来构造一个新的类型。
type MyExclude<T, U> = T extends U ? never:  T

// 3. 实现 Pick ，从类型 T 中选择出属性 K，构造成一个新的类型。
type MyPick<T, K extends keyof T> = {
  [P in K]: T[P];
}

// 4. 实现 Extract ，跟 Exclude 相反，提取 类型T 和 类型U 的交集
type MyExtract<T, U> = T extends U ? T : never

// 5. 实现 Record ，接收两个泛型参数；Record后面的泛型就是对象键和值的类型
// type MyRecord<K extends string | number | symbol, V> = {
//   [P in K] : V
// }
type MyRecord<K extends keyof any, T> = {
  [P in K]: T;
}
// 6. 实现 Partial ，生成一个新类型，该类型与 T 拥有相同的属性，但是所有属性皆为可选项
type MyPartial<U> = {
  [K in keyof U]?:U[K]
}

// 7. 实现 Required ，生成一个新类型，该类型与 T 拥有相同的属性，但是所有属性皆为必选
type MyRequired<U> = {
  [K in keyof U]-?:U[K]
}

// 8. 实现 Readonly ，使T中的所有属性只读
type MyReadonly<T> = {
  readonly [K in keyof T]: T[K]
}

// 9. 实现 Omit ，创建一个省略 K 字段的 T 对象
type MyOmit<T,K extends keyof T> = {
  [P in Exclude<keyof T,K>] :T[P]
}

// 9. 实现 NonNullable ，从泛型 T 中排除掉 null 和 undefined
// type MyNonNullable<T> = T extends null | undefined ? never : T
type MyNonNullable<T> = T & {};

// 10. 实现 Parameters ， 以元组的方式获得函数的入参类型
type MyParameters<T extends (...args:any) => any> = T extends (...args:infer Arg) => any ? Arg : never

// 11. 实现 ConstructorParameters ， 以元组的方式获得构造函数函数的入参类型
type MyConstructorParameters<T extends abstract new (...args: any) => any> = T extends abstract new (...args:infer Arg) => any ? Arg : never

// 12. 实现 InstanceType ， 获得构造函数返回值的类型
type MyInstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args:any) => infer Return ? Return : never

// 13.实现泛型 GetReadonlyKeys ，GetReadonlyKeys<T>返回由对象 T 所有只读属性的键组成的联合类型。
// 全等
type IsEqual<X, Y> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false

type GetReadonlyKeys<T, K = keyof T> = K extends keyof T
  ? IsEqual<Pick<T, K>, MyReadonly<Pick<T, K>>> extends true
    ? K
    : never
  : never

